use super::*;

/// A [Contextual Lookup Subtable](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#seqctxt1).
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy)]
pub enum ContextLookup<'a> {
	/// Simple glyph contexts.
	Format1 {
		coverage: Coverage<'a>,
		sets: SequenceRuleSets<'a>,
	},
	/// Class-based glyph contexts.
	Format2 {
		coverage: Coverage<'a>,
		classes: ClassDefinition<'a>,
		sets: SequenceRuleSets<'a>,
	},
	/// Coverage-based glyph contexts.
	Format3 {
		coverage: Coverage<'a>,
		coverages: LazyOffsetArray16<'a, Coverage<'a>>,
		lookups: LazyArray16<'a, SequenceLookupRecord>,
	},
}

impl<'a> ContextLookup<'a> {
	pub(crate) fn parse(data: &'a [u8]) -> Option<Self> {
		let mut s = Stream::new(data);
		match s.read::<u16>()? {
			1 => Some(Self::Format1 {
				coverage: s.parse_at_offset16(data)?,
				sets: SequenceRuleSets::new(data, s.parse_array16()?),
			}),
			2 => Some(Self::Format2 {
				coverage: s.parse_at_offset16(data)?,
				classes: s.parse_at_offset16(data)?,
				sets: SequenceRuleSets::new(data, s.parse_array16()?),
			}),
			3 => {
				let input_count = s.read::<u16>()?;
				let lookup_count = s.read::<u16>()?;
				Some(Self::Format3 {
					coverage: s.parse_at_offset16(data)?,
					coverages: LazyOffsetArray16::new(data, s.read_array16(input_count.checked_sub(1)?)?),
					lookups: s.read_array16(lookup_count)?,
				})
			}
			_ => None,
		}
	}

	/// Returns the subtable coverage.
	#[inline]
	pub fn coverage(&self) -> Coverage<'a> {
		match self {
			Self::Format1 { coverage, .. } => *coverage,
			Self::Format2 { coverage, .. } => *coverage,
			Self::Format3 { coverage, .. } => *coverage,
		}
	}
}

/// A list of [`SequenceRuleSet`]s.
pub type SequenceRuleSets<'a> = LazyOffsetArray16<'a, SequenceRuleSet<'a>>;

/// A set of [`SequenceRule`]s.
pub type SequenceRuleSet<'a> = LazyOffsetArray16<'a, SequenceRule<'a>>;

/// A sequence rule.
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
pub struct SequenceRule<'a> {
	pub input: LazyArray16<'a, u16>,
	pub lookups: LazyArray16<'a, SequenceLookupRecord>,
}
impl<'a> FromSlice<'a> for SequenceRule<'a> {
	fn parse(data: &'a [u8]) -> Option<Self> {
		let mut s = Stream::new(data);
		let input_count = s.read::<u16>()?;
		let lookup_count = s.read::<u16>()?;
		Some(Self {
			input: s.read_array16(input_count.checked_sub(1)?)?,
			lookups: s.read_array16(lookup_count)?,
		})
	}
}

/// A sequence rule record.
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
pub struct SequenceLookupRecord {
	pub sequence_index: u16,
	pub lookup_list_index: u16,
}
impl FromData for SequenceLookupRecord {
	const SIZE: usize = 4;
	#[inline]
	fn parse(data: &[u8]) -> Option<Self> {
		let mut s = Stream::new(data);
		Some(Self {
			sequence_index: s.read::<u16>()?,
			lookup_list_index: s.read::<u16>()?,
		})
	}
}
